﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;

using System.Security.Cryptography;

namespace CPlase
{
    /// <summary>
    /// Набор утилит для служб безопасности
    /// </summary>
    public static class Security
    {

        public readonly static char[] DefaultAlfabet = {
            'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l',
            'm', 'n', 'o', 'p', 'q', 'r',
            's', 't', 'u', 'v', 'w', 'x',
            'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F',
            'G', 'H', 'I', 'J', 'K', 'L',
            'M', 'N', 'O', 'P', 'Q', 'R',
            'S', 'T', 'U', 'V', 'W', 'X',
            'Y', 'Z',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

        public readonly static char[] SmallLettersAlfabet = {
            'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l',
            'm', 'n', 'o', 'p', 'q', 'r',
            's', 't', 'u', 'v', 'w', 'x',
            'y', 'z'};

        private readonly static Random IntegerRandom = new Random();

        /// <summary>
        /// Генерирует и возвращает слово заданного размера заданного алфавита
        /// </summary>
        /// <param name="MinLength">Минимальная длинна слова</param>
        /// <param name="MaxLength">Максимальная длинна слова</param>
        /// <param name="Alfabet">Массив символов алфавита. Если null или не задано используется стандартный алфавит поумолчанию</param>
        /// <returns>Слово, сгенерированное из букв алфавита с помощью Random</returns>
        public static string GenerateWord(uint MinLength = 30, uint MaxLength = 40, char[] Alfabet = null)
        {
            if (Alfabet == null) Alfabet = DefaultAlfabet;

            int WordLength = IntegerRandom.Next((int)MinLength, (int)MaxLength);

            string ResultWord = "";

            int AlfabetLength = Alfabet.Length;
            for (int i = 0; i < WordLength; i++)
            {
                char NewChar = Alfabet[IntegerRandom.Next(0, AlfabetLength - 1)];
                ResultWord += NewChar;
            }
            return ResultWord;
        }

        /// <summary>
        /// Возвращает случайный символ из заданого алфавита.
        /// Если алфавит null или не задан, используется стандартный алфавит поумолчанию
        /// </summary>
        /// <param name="Alfabet">Массив символов алфавита</param>
        /// <returns>Случайный символ из алфавита</returns>
        public static char GetRandomChar(char[] Alfabet = null)
        {
            if (Alfabet == null) Alfabet = DefaultAlfabet;
            return Alfabet[IntegerRandom.Next(0, Alfabet.Length - 1)]; ;
        }

        /// <summary>
        /// SHA1-хеш
        /// </summary>
        /// <param name="Input">Строка которая будет хеширована</param>
        /// <returns>SHA1-хеш</returns>
        public static string GetHashSHA1(string Input)
        {
            return BitConverter.ToString(new SHA1CryptoServiceProvider().ComputeHash(
                Encoding.Default.GetBytes(Input))).Replace("-", String.Empty);
        }

        /// <summary>
        /// MD5-хеш, ззписанный в стринге
        /// </summary>
        /// <param name="Input"></param>
        /// <returns></returns>
        public static string GetHashMD5(string Input)
        {
            if (Input == null) return null;
            return BitConverter.ToString(MD5.Create().ComputeHash(
                Encoding.Default.GetBytes(Input))).Replace("-", String.Empty);
        }

        /// <summary>
        /// Возвращает заданное количество бит из MD5-хеша
        /// </summary>
        /// <param name="Input">Строка, которая будет закеширована</param>
        /// <param name="BitCount">Количество бит, которое будет возвращено из хеша (по-умолчанию 128)</param>
        /// <returns>Заданное количество бит из MD5-хеша
        /// 
        /// Пример:
        ///     input = novvad@gmail.com
        ///     BitCount = 14
        ///     retrun 00010110101000	
        /// 
        ///     input = berd.na@gmail.com
        ///     BitCount = 14
        ///     10100010011000
        /// </returns>
        public static string GetHashMD5Binary(string Input, int BitCount = 128)
        {
            if (Input == null) return null;
            byte[] MD5Bytes = MD5.Create().ComputeHash(
                Encoding.Default.GetBytes(Input));

            int Len = MD5Bytes.Length;

            string Result = "";

            int HasBits = 0;

            for (int i = 0; i < Len; i++)
            {
                Result += Convert.ToString(MD5Bytes[i], 2).PadLeft(8, '0');
                HasBits += 8;
                if (HasBits >= BitCount) break;
            }

            if (BitCount < 1 || BitCount >= 128) return Result;
            return Result.Substring(0, BitCount);
        }

        /// <summary>
        /// Проверка, является ли заданный хеш MD5-хешем от заданной строки
        /// </summary>
        /// <param name="Input">Строка которая будет захеширована MD5-хешем</param>
        /// <param name="Hash">Хеш с которым будет сравниваться захешированная строка Input</param>
        /// <returns>Возвращает true, если хеш от строки совпал с хешов</returns>
        public static bool VerifyHashMD5(string Input, string Hash)
        {
            // Hash the input.
            string hashOfInput = GetHashMD5(Input);

            // Create a StringComparer an compare the hashes.
            StringComparer comparer = StringComparer.OrdinalIgnoreCase;

            if (0 == comparer.Compare(hashOfInput, Hash))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private const string VerifyCodeSalt = @"f0%m0wvU|~%{C4|@6yZem*Oay";

        public static string GenerateVerifyCode()
        {
            string Out = "";
            Out = GetHashMD5(DateTime.UtcNow.ToString() + VerifyCodeSalt).ToLowerInvariant();
            return Out;
        }

        public static string GetProtocol(HttpRequest Request)
        {
            return Request.IsSecureConnection ? "https://" : "http://";
        }

        public static string GetProtocol(HttpRequestBase Request)
        {
            return Request.IsSecureConnection ? "https://" : "http://";
        }

        public static string GetHost(HttpRequest Request)
        {
            return Request.IsSecureConnection ? "https://www.atcontent.com/" : "http://www.atcontent.com/";
        }

        public static string GetHost(HttpRequestBase Request)
        {
            return Request.IsSecureConnection ? "https://www.atcontent.com/" : "http://www.atcontent.com/";
        }

    }
}